#pragma once
#include <d3d11_1.h>
#include "DXContext.h"
#include "enums.h"
#include "primitives.h"
#include "DataArray.h"

namespace DXBase
{
	namespace D3D
	{
		[Windows::Foundation::Metadata::WebHostHidden]
		public ref class SamplerState sealed : IContextBound
		{
		private:
			CD3D11_SAMPLER_DESC desc;
			DXBase::ContextWatcher watcher;

		internal:
			inline virtual void Reset() = IContextBound::ClearDXData { mState = nullptr; }
			virtual void Reload() = IContextBound::LoadDXData;
			virtual property DXContext^ Context
			{
				DXContext^ get() = IContextBound::Context::get { return watcher.Context; } 
				void set(DXContext^ ctxt) = IContextBound::Context::set { watcher.Context = ctxt; }
			}

			Microsoft::WRL::ComPtr<ID3D11SamplerState> mState;

		public:
			SamplerState();


			property DXBase::D3D::FILTER Filter 
			{
				DXBase::D3D::FILTER get() { return static_cast<DXBase::D3D::FILTER>(desc.Filter); }
				void set(DXBase::D3D::FILTER value)
				{
					desc.Filter = static_cast<D3D11_FILTER>(value);
					Reset();
				}
			}
			property DXBase::D3D::TEXTURE_ADDRESS_MODE U 
			{
				DXBase::D3D::TEXTURE_ADDRESS_MODE get() { return static_cast<DXBase::D3D::TEXTURE_ADDRESS_MODE>(desc.AddressU); }
				void set(DXBase::D3D::TEXTURE_ADDRESS_MODE value)
				{
					if (!IsTEXTURE_ADDRESS_MODE(value))
						return;
					desc.AddressU = static_cast<D3D11_TEXTURE_ADDRESS_MODE>(value);
					Reset();
				}
			}
			property DXBase::D3D::TEXTURE_ADDRESS_MODE V 
			{
				DXBase::D3D::TEXTURE_ADDRESS_MODE get() { return static_cast<DXBase::D3D::TEXTURE_ADDRESS_MODE>(desc.AddressV); }
				void set(DXBase::D3D::TEXTURE_ADDRESS_MODE value)
				{
					if (!IsTEXTURE_ADDRESS_MODE(value))
						return;
					desc.AddressU = static_cast<D3D11_TEXTURE_ADDRESS_MODE>(value);
					Reset();
				}
			}
			property DXBase::D3D::TEXTURE_ADDRESS_MODE W
			{
				DXBase::D3D::TEXTURE_ADDRESS_MODE get() { return static_cast<DXBase::D3D::TEXTURE_ADDRESS_MODE>(desc.AddressW); }
				void set(DXBase::D3D::TEXTURE_ADDRESS_MODE value)
				{
					if (!IsTEXTURE_ADDRESS_MODE(value))
						return;
					desc.AddressU = static_cast<D3D11_TEXTURE_ADDRESS_MODE>(value);
					Reset();
				}
			}
			property float MipLODBias
			{
				float get() { return desc.MipLODBias; }
				void set(float value)
				{
					desc.MipLODBias = value;
					Reset();
				}
			}
			property UINT MaxAnisotropy
			{
				UINT get() { return desc.MaxAnisotropy; }
				void set(UINT value)
				{
					desc.MaxAnisotropy = value;
					Reset();
				}
			}
			property DXBase::D3D::COMPARISON_FUNC ComparisonFunc
			{
				DXBase::D3D::COMPARISON_FUNC get() { return static_cast<DXBase::D3D::COMPARISON_FUNC>(desc.ComparisonFunc); }
				void set(DXBase::D3D::COMPARISON_FUNC value)
				{
					if (!IsCOMPARISON_FUNC(value))
						return;
					desc.ComparisonFunc = static_cast<D3D11_COMPARISON_FUNC>(value);
					Reset();
				}
			}
			property float4 BorderColor
			{
				float4 get() { return vector4(desc.BorderColor[0], desc.BorderColor[1], desc.BorderColor[2], desc.BorderColor[3]); }
				void set(float4 value)
				{
					desc.BorderColor[0] = value.x;
					desc.BorderColor[1] = value.y;
					desc.BorderColor[2] = value.z;
					desc.BorderColor[3] = value.w;
					Reset();
				}
			}
			property float MinLOD
			{
				float get() { return desc.MinLOD; }
				void set(float value)
				{
					desc.MinLOD = value;
					Reset();
				}
			}
			property float MaxLOD
			{
				float get() { return desc.MaxLOD; }
				void set(float value)
				{
					desc.MaxLOD = value;
					Reset();
				}
			}
		};

		[Windows::Foundation::Metadata::WebHostHidden]
		public ref class RasterizerState sealed : IContextBound
		{
		private:
			CD3D11_RASTERIZER_DESC desc;
			DXBase::ContextWatcher watcher;

		internal:
			Microsoft::WRL::ComPtr<ID3D11RasterizerState> mState;
			inline virtual void Reset() = IContextBound::ClearDXData { mState = nullptr; }
			virtual void Reload() = IContextBound::LoadDXData;
			virtual property DXContext^ Context
			{
				DXContext^ get() = IContextBound::Context::get { return watcher.Context; } 
				void set(DXContext^ ctxt) = IContextBound::Context::set { watcher.Context = ctxt; }
			}

		public:
			RasterizerState();

			property bool Wireframe 
			{
				bool get() { return desc.FillMode == D3D11_FILL_WIREFRAME; }
				void set(bool value)
				{
					desc.FillMode = value ? D3D11_FILL_WIREFRAME : D3D11_FILL_SOLID;
					Reset();
				}
			}
			property DXBase::D3D::FILL_MODE FILL_MODE 
			{
				DXBase::D3D::FILL_MODE get() { return static_cast<DXBase::D3D::FILL_MODE>(desc.FillMode); }
				void set(DXBase::D3D::FILL_MODE value)
				{
					if (!IsFILL_MODE(value))
						return;
					desc.FillMode = static_cast<D3D11_FILL_MODE>(value);
					Reset();
				}
			}
			property DXBase::D3D::CULL_MODE CULL_MODE 
			{
				DXBase::D3D::CULL_MODE get() { return static_cast<DXBase::D3D::CULL_MODE>(desc.CullMode); }
				void set(DXBase::D3D::CULL_MODE value)
				{
					if (!IsCULL_MODE(value))
						return;
					desc.CullMode = static_cast<D3D11_CULL_MODE>(value);
					Reset();
				}
			}
			property bool FrontCounterClockwise 
			{
				bool get() { return desc.FrontCounterClockwise ? true : false; }
				void set(bool value)
				{
					desc.FrontCounterClockwise = value;
					Reset();
				}
			}
			property int32 DepthBias
			{
				int32 get() { return desc.DepthBias; }
				void set(int32 value)
				{
					desc.DepthBias = value;
					Reset();
				}
			}
			property float DepthBiasClamp
			{
				float get() { return desc.DepthBiasClamp; }
				void set(float value)
				{
					desc.DepthBiasClamp = value;
					Reset();
				}
			}
			property float MaxLOD
			{
				float get() { return desc.SlopeScaledDepthBias; }
				void set(float value)
				{
					desc.SlopeScaledDepthBias = value;
					Reset();
				}
			}
			property bool DepthClipEnable 
			{
				bool get() { return desc.DepthClipEnable ? true : false; }
				void set(bool value)
				{
					desc.DepthClipEnable = value;
					Reset();
				}
			}
			property bool ScissorEnable 
			{
				bool get() { return desc.ScissorEnable ? true : false; }
				void set(bool value)
				{
					desc.ScissorEnable = value;
					Reset();
				}
			}
			property bool MultisampleEnable 
			{
				bool get() { return desc.MultisampleEnable ? true : false; }
				void set(bool value)
				{
					desc.MultisampleEnable = value;
					Reset();
				}
			}
			property bool AntialiasedLineEnable 
			{
				bool get() { return desc.AntialiasedLineEnable ? true : false; }
				void set(bool value)
				{
					desc.AntialiasedLineEnable = value;
					Reset();
				}
			}
		};

		[Windows::Foundation::Metadata::WebHostHidden]
		public ref class BlendState sealed : IContextBound
		{
		private:
			CD3D11_BLEND_DESC desc;
			DXBase::ContextWatcher watcher;
			DataPointerView<RENDER_TARGET_BLEND_DESC>^ pRenderTargets;

		internal:
			Microsoft::WRL::ComPtr<ID3D11BlendState> mState;
			inline virtual void Reset() = IContextBound::ClearDXData { mState = nullptr; }
			virtual void Reload() = IContextBound::LoadDXData;
			virtual property DXContext^ Context
			{
				DXContext^ get() = IContextBound::Context::get { return watcher.Context; } 
				void set(DXContext^ ctxt) = IContextBound::Context::set { watcher.Context = ctxt; }
			}

		public:
			BlendState();

			property bool AlphaToCoverageEnable 
			{
				bool get() { return desc.AlphaToCoverageEnable ? true : false; }
				void set(bool value)
				{
					desc.AlphaToCoverageEnable = value;
					Reset();
				}
			}
			property bool IndependentBlendEnable 
			{
				bool get() { return desc.IndependentBlendEnable ? true : false; }
				void set(bool value)
				{
					desc.IndependentBlendEnable = value;
					Reset();
				}
			}
			property Windows::Foundation::Collections::IVector<RENDER_TARGET_BLEND_DESC>^ RenderTargets
			{
				Windows::Foundation::Collections::IVector<RENDER_TARGET_BLEND_DESC>^ get() { return pRenderTargets; }
			}
		};

		[Windows::Foundation::Metadata::WebHostHidden]
		public ref class DepthStencilState sealed : IContextBound
		{
		private:
			CD3D11_DEPTH_STENCIL_DESC desc;
			DXBase::ContextWatcher watcher;

		internal:
			Microsoft::WRL::ComPtr<ID3D11DepthStencilState> mState;
			inline virtual void Reset() = IContextBound::ClearDXData { mState = nullptr; }
			virtual void Reload() = IContextBound::LoadDXData;
			virtual property DXContext^ Context
			{
				DXContext^ get() = IContextBound::Context::get { return watcher.Context; } 
				void set(DXContext^ ctxt) = IContextBound::Context::set { watcher.Context = ctxt; }
			}

		public:
			DepthStencilState();

			property bool DepthWrite
			{
				bool get() { return desc.DepthWriteMask != D3D11_DEPTH_WRITE_MASK_ZERO; }
				void set(bool value)
				{
					desc.DepthWriteMask = value ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO;
					Reset();
				}
			}
			property DXBase::D3D::DEPTH_WRITE_MASK DepthWriteMask 
			{
				DXBase::D3D::DEPTH_WRITE_MASK get() { return static_cast<DXBase::D3D::DEPTH_WRITE_MASK>(desc.DepthWriteMask); }
				void set(DXBase::D3D::DEPTH_WRITE_MASK value)
				{
					desc.DepthWriteMask = static_cast<D3D11_DEPTH_WRITE_MASK>(value);
					Reset();
				}
			}
			property DXBase::D3D::COMPARISON_FUNC DepthFunc
			{
				DXBase::D3D::COMPARISON_FUNC get() { return static_cast<DXBase::D3D::COMPARISON_FUNC>(desc.DepthFunc); }
				void set(DXBase::D3D::COMPARISON_FUNC value)
				{
					if (!IsCOMPARISON_FUNC(value))
						return;
					desc.DepthFunc = static_cast<D3D11_COMPARISON_FUNC>(value);
					Reset();
				}
			}
			property bool StencilEnable 
			{
				bool get() { return desc.StencilEnable ? true : false; }
				void set(bool value)
				{
					desc.StencilEnable = value;
					Reset();
				}
			}
			property UINT8 StencilReadMask 
			{
				UINT8 get() { return desc.StencilReadMask; }
				void set(UINT8 value)
				{
					desc.StencilReadMask = value;
					Reset();
				}
			}
			property UINT8 StencilWriteMask 
			{
				UINT8 get() { return desc.StencilWriteMask; }
				void set(UINT8 value)
				{
					desc.StencilWriteMask = value;
					Reset();
				}
			}
			property DEPTH_STENCILOP_DESC FrontFace 
			{
				DEPTH_STENCILOP_DESC get() 
				{
					DEPTH_STENCILOP_DESC result;
					InitSrcDst(desc.FrontFace, result);
					return result;
				}
				void set(DEPTH_STENCILOP_DESC value)
				{
					InitSrcDst(value, desc.FrontFace);
					Reset();
				}
			}
			property DEPTH_STENCILOP_DESC BackFace 
			{
				DEPTH_STENCILOP_DESC get() 
				{
					DEPTH_STENCILOP_DESC result;
					InitSrcDst(desc.BackFace, result);
					return result;
				}
				void set(DEPTH_STENCILOP_DESC value)
				{
					InitSrcDst(value, desc.BackFace);
					Reset();
				}
			}
		};
	}
}

